package ru.mcfr.oxygen.framework.extensions;

import org.apache.log4j.Logger;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import ro.sync.ecss.extensions.api.AuthorAccess;
import ro.sync.ecss.extensions.api.AuthorReferenceResolver;
import ro.sync.ecss.extensions.api.node.AttrValue;
import ro.sync.ecss.extensions.api.node.AuthorElement;
import ro.sync.ecss.extensions.api.node.AuthorNode;

import javax.xml.transform.sax.SAXSource;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * References resolver for Simple Documentation Framework.
 */
public class MOFReferencesResolver implements AuthorReferenceResolver {
    /**
     * Logger for logging.
     */
    private static Logger logger = Logger.getLogger(
            MOFReferencesResolver.class.getName());

    private String linkTagName = "в_ссылка";
    private String targetTagName = "в_цель";
    private String linkToContentAttrName = "элемент";
    private String linkToDocumentAttrName = "документ";

    public boolean hasReferences(AuthorNode node) {
        boolean hasReferences = false;
        if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) {
            AuthorElement element = (AuthorElement) node;
            if (linkTagName.equals(element.getLocalName())) {
                AuthorElement targetElement = element.getElementsByLocalName(targetTagName)[0];
                AttrValue linkToDocument = targetElement.getAttribute(linkToDocumentAttrName);
                AttrValue linkToContent = targetElement.getAttribute(linkToContentAttrName);
                hasReferences = (linkToDocument != null) & (linkToContent != null);
            }
        }
        return hasReferences;
    }

    public String getDisplayName(AuthorNode node) {
        String displayName = "внешняя ссылка";
        if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) {
            AuthorElement element = (AuthorElement) node;
            if (linkTagName.equals(element.getLocalName())) {
                AuthorElement targetElement = element.getElementsByLocalName(targetTagName)[0];
                AttrValue linkToDocument = targetElement.getAttribute(linkToDocumentAttrName);
                AttrValue linkToContent = targetElement.getAttribute(linkToContentAttrName);
                if ((linkToDocument != null) & (linkToContent != null)) {
                    displayName = "документ:" + linkToDocument + "@";
                    displayName += "элемент:" + linkToContent;
                }
            }
        }
        return displayName;
    }

    public SAXSource resolveReference(
            AuthorNode node,
            String systemID,
            AuthorAccess authorAccess,
            EntityResolver entityResolver) {
        SAXSource saxSource = null;
        if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) {
            AuthorElement element = (AuthorElement) node;
            if (linkTagName.equals(element.getLocalName())) {
                AuthorElement targetElement = element.getElementsByLocalName(targetTagName)[0];
                AttrValue linkToDocument = targetElement.getAttribute(linkToDocumentAttrName);
                AttrValue linkToContent = targetElement.getAttribute(linkToContentAttrName);

                AttrValue attrValue = element.getAttribute("location");
                if ((linkToDocument != null) & (linkToContent != null)) {
                    String linkToDocumentStringVal = linkToDocument.getValue();
                    String linkToContentStringVal = linkToContent.getValue();
                    if ((linkToDocumentStringVal.length() > 0) & (linkToContentStringVal.length() > 0)) {
                        try {
                            URL absoluteUrl = new URL(new URL(systemID),
                                    authorAccess.getUtilAccess().correctURL(linkToDocumentStringVal));
                            InputSource inputSource = entityResolver.resolveEntity(null,
                                    absoluteUrl.toString());
                            if (inputSource == null) {
                                inputSource = new InputSource(absoluteUrl.toString());
                            }
                            XMLReader xmlReader = authorAccess.getXMLUtilAccess().newNonValidatingXMLReader();
                            xmlReader.setEntityResolver(entityResolver);
                            saxSource = new SAXSource(xmlReader, inputSource);
                        } catch (MalformedURLException e) {
                            logger.error(e, e);
                        } catch (SAXException e) {
                            logger.error(e, e);
                        } catch (IOException e) {
                            logger.error(e, e);
                        }
                    }
                }
            }
        }
        return saxSource;
    }

    public String getReferenceUniqueID(AuthorNode node) {
        String id = null;
        if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) {
            AuthorElement element = (AuthorElement) node;
            if (linkTagName.equals(element.getLocalName())) {
                AttrValue attrValue = element.getAttribute("location");
                if (attrValue != null) {
                    id = attrValue.getValue();
                }
            }
        }
        return id;
    }

    public String getReferenceSystemID(AuthorNode node,
                                       AuthorAccess authorAccess) {
        String systemID = null;
        if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) {
            AuthorElement element = (AuthorElement) node;
            if (linkTagName.equals(element.getLocalName())) {
                AttrValue attrValue = element.getAttribute("location");
                if (attrValue != null) {
                    String attrStringVal = attrValue.getValue();
                    try {
                        URL absoluteUrl = new URL(node.getXMLBaseURL(),
                                authorAccess.getUtilAccess().correctURL(attrStringVal));
                        systemID = absoluteUrl.toString();
                    } catch (MalformedURLException e) {
                        logger.error(e, e);
                    }
                }
            }
        }
        return systemID;
    }

    public boolean isReferenceChanged(AuthorNode node, String attributeName) {
        return "location".equals(attributeName);
    }

    public String getDescription() {
        return "Обработчик внешних ссылок";
    }
}
